﻿namespace DomainServices.Tools
{
    using System;
    using System.CodeDom;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.ServiceModel.DomainServices;
    using System.ServiceModel.DomainServices.Server;
    using System.ServiceModel.DomainServices.Server.ApplicationServices;

    internal class WebContextGenerator : ProxyGenerator
    {
        internal WebContextGenerator(CodeDomClientCodeGenerator proxyGenerator) : base(proxyGenerator)
        {
        }

        public override void Generate()
        {
            CodeNamespace orGenNamespace = base.ClientProxyGenerator.GetOrGenNamespace(base.ClientProxyGenerator.ClientProxyCodeGenerationOptions.ClientRootNamespace);
            if (orGenNamespace != null)
            {
                base.ClientProxyGenerator.LogMessage(DomainServices.Tools.Resource.CodeGen_Generating_WebContext);
                IEnumerable<DomainServiceDescription> source = from d in base.ClientProxyGenerator.DomainServiceDescriptions
                    where typeof(IAuthentication<>).DefinitionIsAssignableFrom(d.DomainServiceType)
                    select d;
                DomainServiceDescription description = null;
                if (source.Count<DomainServiceDescription>() > 1)
                {
                    object[] args = new object[] { string.Join(",", (from d in source select d.DomainServiceType.Name).ToArray<string>()) };
                    base.ClientProxyGenerator.LogMessage(string.Format(CultureInfo.InvariantCulture, DomainServices.Tools.Resource.WebContext_ManyAuthServices, args));
                }
                else
                {
                    description = source.FirstOrDefault<DomainServiceDescription>();
                }
                CodeTypeDeclaration declaration = CodeGenUtilities.CreateTypeDeclaration("WebContext", orGenNamespace.Name);
                declaration.IsPartial = true;
                declaration.TypeAttributes = TypeAttributes.Sealed | TypeAttributes.Public;
                declaration.BaseTypes.Add(CodeGenUtilities.GetTypeReference("System.ServiceModel.DomainServices.Client.ApplicationServices.WebContextBase", orGenNamespace.Name, false));
                declaration.Comments.AddRange(CodeGenUtilities.GetDocComments(DomainServices.Tools.Resource.WebContext_CommentClass, base.ClientProxyGenerator.IsCSharp));
                orGenNamespace.Types.Add(declaration);
                CodeConstructor constructor = new CodeConstructor {
                    Attributes = MemberAttributes.Public
                };
                NotificationMethodGenerator generator = new NotificationMethodGenerator(base.ClientProxyGenerator, base.ClientProxyGenerator.IsCSharp ? IndentationLevel.Namespace : IndentationLevel.GlobalNamespace);
                constructor.Statements.Add(generator.OnCreatedMethodInvokeExpression);
                constructor.Comments.AddRange(CodeGenUtilities.GetDocComments(DomainServices.Tools.Resource.WebContext_CommentConstructor, base.ClientProxyGenerator.IsCSharp));
                declaration.Members.Add(constructor);
                declaration.Members.AddRange(generator.PartialMethodsSnippetBlock);
                CodeMemberProperty property = new CodeMemberProperty();
                CodeTypeReference reference = CodeGenUtilities.GetTypeReference((string.IsNullOrEmpty(orGenNamespace.Name) ? string.Empty : (orGenNamespace.Name + ".")) + "WebContext", orGenNamespace.Name, true);
                CodeTypeReferenceExpression targetObject = new CodeTypeReferenceExpression(CodeGenUtilities.GetTypeReference("System.ServiceModel.DomainServices.Client.ApplicationServices.WebContextBase", orGenNamespace.Name, false));
                property.Attributes = MemberAttributes.Public | MemberAttributes.New | MemberAttributes.Static;
                property.Type = reference;
                property.Name = "Current";
                property.HasGet = true;
                property.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(property.Type, new CodePropertyReferenceExpression(targetObject, "Current"))));
                property.Comments.AddRange(CodeGenUtilities.GetDocComments(DomainServices.Tools.Resource.WebContext_CommentCurrent, base.ClientProxyGenerator.IsCSharp));
                declaration.Members.Add(property);
                if (description != null)
                {
                    Type genericType = null;
                    typeof(IAuthentication<>).DefinitionIsAssignableFrom(description.DomainServiceType, out genericType);
                    if ((genericType != null) && (genericType.GetGenericArguments().Count<Type>() == 1))
                    {
                        CodeMemberProperty property2 = new CodeMemberProperty {
                            Attributes = MemberAttributes.Public | MemberAttributes.New | MemberAttributes.Final,
                            Type = CodeGenUtilities.GetTypeReference(genericType.GetGenericArguments()[0], base.ClientProxyGenerator, declaration),
                            Name = "User",
                            HasGet = true
                        };
                        property2.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(property2.Type, new CodePropertyReferenceExpression(new CodeBaseReferenceExpression(), "User"))));
                        property2.Comments.AddRange(CodeGenUtilities.GetDocComments(DomainServices.Tools.Resource.WebContext_CommentUser, base.ClientProxyGenerator.IsCSharp));
                        declaration.Members.Add(property2);
                    }
                }
            }
        }
    }
}

